﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Web;
using System.Security.Cryptography;

namespace BPMS.Utility.ValidateCode
{
    public class CaptchaUtility
    {
        private static FontStyle[] fontStyleList;
        private static string[] fontNameList;
        private static Dictionary<Brush, string> dicBrush;
        private readonly Random random = new Random(~unchecked((int)DateTime.Now.Ticks));
        /// <summary>
        /// 验证码位数
        /// </summary>
        private const int CharCount = 5;
        /// <summary>
        /// 验证码单个字符高度
        /// </summary>
        private const int CharHeight = 20;
        /// <summary>
        /// 验证码单个字符宽度
        /// </summary>
        private const int CharWidth = 16;
        /// <summary>
        /// 背景色
        /// </summary>
        private readonly static Color BackColor = Color.White;

        /// <summary>
        /// 验证码 
        /// </summary>
        public string Captcha { get; private set; }

        static CaptchaUtility()
        {
            fontStyleList = new FontStyle[] { FontStyle.Regular, FontStyle.Italic, FontStyle.Bold, FontStyle.Regular | FontStyle.Bold, FontStyle.Italic | FontStyle.Bold };
            fontNameList = new string[] { "Arial", "Comic Sans MS", "Times New Roman", "Georgia" };
            dicBrush = new Dictionary<Brush, string>() 
            { 
                {Brushes.OliveDrab,"OliveDrab"},
                {Brushes.ForestGreen,"ForestGreen"},
                {Brushes.DarkCyan,"DarkCyan"},
                {Brushes.LightSlateGray,"LightSlateGray"},
                {Brushes.RoyalBlue,"RoyalBlue"},
                {Brushes.SlateBlue,"SlateBlue"},
                {Brushes.DarkViolet,"DarkViolet"},
                {Brushes.MediumVioletRed,"MediumVioletRed"},
                {Brushes.IndianRed,"IndianRed"},
                {Brushes.Firebrick,"Firebrick"},
                {Brushes.Chocolate,"Chocolate"},
                {Brushes.Peru,"Peru"},
                {Brushes.Goldenrod,"Goldenrod"}
            };
        }

        /// <summary>
        /// 获取随机的字体
        /// </summary>
        /// <returns></returns>
        private Font GetNextFont()
        {
            string name = fontNameList[random.Next(0, fontNameList.Length - 1)];
            int size = random.Next(13, 14);
            FontStyle style = fontStyleList[random.Next(0, fontStyleList.Length - 1)];
            return new Font(new FontFamily(name), size, style);
        }

        /// <summary>
        /// 获取随机画刷
        /// </summary>
        /// <returns></returns>
        private Brush GetNextBrush()
        {
            return RandomHelper.NextItem<Brush>(dicBrush.Keys);
        }

        /// <summary>
        /// 
        /// </summary>
        public Bitmap DrawCodeImage()
        {
            Bitmap bitmap = new Bitmap(CharWidth * CharCount, CharHeight);
            Graphics graphics = Graphics.FromImage(bitmap);
            graphics.Clear(BackColor);
            DrawRandomLine(graphics);
            DrawRandomData(graphics);
            DrawRectangleLine(graphics);
            DrawPixel(bitmap);
            return bitmap;
        }

        /// <summary>
        /// 绘制噪音点
        /// </summary>
        /// <param name="bitmap"></param>
        public void DrawPixel(Bitmap bitmap)
        {
            for (int i = 0; i < 200; i++)
            {
                int x = random.Next(CharWidth * CharCount);
                int y = random.Next(CharHeight);
                bitmap.SetPixel(x, y, System.Drawing.Color.FromArgb(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)));
            }
        }

        /// <summary>
        /// 绘制边框线
        /// </summary>
        /// <param name="graphics"></param>
        public void DrawRectangleLine(Graphics graphics)
        {
            graphics.DrawRectangle(new Pen(GetNextBrush(), 1), 0, 0, CharWidth * CharCount - 1, CharHeight - 1);
        }

        /// <summary>
        /// 绘制随机的线条
        /// </summary>
        /// <param name="graphics"></param>
        public void DrawRandomLine(Graphics graphics)
        {
            List<Point> pointList = new List<Point>();
            for (int i = 0; i < 5; i++)
            {
                pointList.Add(new Point() { X = RandomX(), Y = RandomY() });
            }
            Pen pen = new Pen(Color.FromArgb(random.Next(160, 200), random.Next(160, 200), random.Next(160, 200)));
            graphics.DrawLines(pen, pointList.ToArray());
        }

        /// <summary>
        /// 绘制随机验证码文本
        /// </summary>
        /// <param name="graphics"></param>
        public void DrawRandomData(Graphics graphics)
        {
            Captcha = RandomHelper.NextAlphaNumeric(CharCount);
            for (int idx = 0; idx < CharCount; idx++)
            {
                graphics.DrawString(Captcha[idx].ToString(), GetNextFont(), GetNextBrush(), new PointF(CharWidth * idx + random.Next(-2, 2), random.Next(-2, 2)));
            }
        }

        /// <summary>
        /// 获取随机X坐标
        /// </summary>
        /// <returns></returns>
        public int RandomX()
        {
            return random.Next(1, CharCount * CharWidth);
        }

        /// <summary>
        /// 获取随机Y坐标
        /// </summary>
        /// <returns></returns>
        public int RandomY()
        {
            return random.Next(1, CharHeight);
        }
    }
}
